﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Data;
using System.Web.UI.WebControls;
using System.Web.Security;

using SmartProject.Data;

namespace SmartProject.BusinessObjects
{
    public class User : Entity
    {
        /// <summary>
        /// Creates a new instance of the User class.
        /// </summary>
        public User()
        {
            DataParameter[] dataParameters = new DataParameter[5];
            dataParameters[0] = new DataParameter("UserId", DataType.Integer);
            dataParameters[1] = new DataParameter("UserName", 300);
            dataParameters[2] = new DataParameter("FirstName", 200);
            dataParameters[3] = new DataParameter("LastName", 150);
            dataParameters[4] = new DataParameter("EMail", 250);

            base.Initialize(dataParameters);

            base.Preferences.Add(new Username());
            base.BusinessRules.Add(new BusinessRules.PasswordCheck());
            base.BusinessRules.Add(new BusinessRules.RemoveUser());
        }

        public void Populate(ListControl listControl)
        {
            listControl.Items.Clear();
            DataTable users = LoadUsers();
            if (users != null)
            {
                foreach (DataRow user in users.Rows)
                {
                    listControl.Items.Add(new ListItem(user["FullName"].ToString(),
                        user["UserId"].ToString()));
                }
            }
        }

        public DataTable LoadUsers()
        {
            return base.Find("smartProject_GetUsers");
        }

        public override void Save()
        {
            base.Run("smartProject_AddUser");
            string userName = (string)base.GetLastAttributeValue("UserName");
            string eMail = (string)base.GetLastAttributeValue("EMail");
            string password = (string)base.GetBusinessRuleParameterValue("Password");
            string roleName = (string)base.GetBusinessRuleParameterValue("Role");
            try
            {
                Membership.CreateUser(userName, password, eMail);
                Roles.AddUserToRole(userName, roleName);
            }
            catch (MembershipCreateUserException membershipCreateUserException)
            {
                // If this is a new install, then we want to remove any accounts there
                // weren't clean out properly. This senerio may only happen during dev,
                // we can consider taking this out after we are in production.
                if (UI.BasePage.IsFirstTimeUserSetup)
                {
                    if (membershipCreateUserException.Message == "The E-mail address is already in use.")
                    {
                        MembershipUserCollection members = Membership.FindUsersByEmail(eMail);
                        if (members.Count == 1)
                        {
                            foreach (MembershipUser member in members)
                            {
                                Membership.DeleteUser(member.UserName, true);
                                const string error = "There was a duplicate e-mail with the same name. We have removed that e-mail. Please restart application.";
                                Logging.Logger.Log("Registration", "AddUser", error, "Critical");
                                throw new Exceptions.BusinessRuleViolation(error);
                            }
                        }
                    }
                }
                Logging.Logger.Log("Registration", "AddUser", membershipCreateUserException.Message, "Warning");
                throw membershipCreateUserException;
            }

            string temporaryUsername = (string)base.GetBusinessRuleParameterValue("TemporaryUserName");
            if (!String.IsNullOrEmpty(temporaryUsername))
            {
                // Remove temp user.
                Membership.DeleteUser(temporaryUsername, true);
            }
        }

        public override void Load()
        {
            if (base.GetAttributeValue("Username") != null)
            {
                base.Load("smartproject_GetUser");
            }
            else
            {
                base.Load("smartproject_GetUserByUserId");
            }
        }

        public override void Update()
        {
            base.Run("smartProject_UpdateUser");

            string userName = (string)base.GetLastAttributeValue("UserName");
            string roleName = (string)base.GetBusinessRuleParameterValue("Role");
            if (!Roles.IsUserInRole(userName, roleName))
            {
                Roles.RemoveUserFromRoles(userName, Roles.GetRolesForUser(userName));
                Roles.AddUserToRole(userName, roleName);
            }
        }

        public override void Remove()
        {
            string userName = (string)GetAttributeValue("UserName");
            base.Run("smartProject_RemoveUser");
            Membership.DeleteUser(userName, true);
        }

        /// <summary>
        /// Creates a temporary user so that we can continue to log into SmartProject to
        /// create a permanent user.
        /// </summary>
        /// <returns>Username of the temporary user.</returns>
        internal static string CreateTemporaryUser()
        {
            // Create a temporary user for purposes of creating a default one.
            string guid = Guid.NewGuid().ToString().Replace("-", "");
            string userName = "Temp_" + guid + "User";
            string password = guid;
            string email = guid + "@smartproject.com";
            Membership.CreateUser(userName, password, email);

            Membership.ValidateUser(userName, password);

            Logging.Logger.Log("User", String.Format("CreateTemporaryUser {0}", userName),
                "Creating temp user.", "Debug");
            return userName;
        }

        internal static void ClearAllUsers()
        {
            bool clearAll = UI.BasePage.IsFirstTimeUserSetup;
            MembershipUserCollection users = Membership.GetAllUsers();
            foreach (MembershipUser user in users)
            {
                // Clear everyone for a clean restart if this is the first time
                // we are setting this up.
                if (clearAll)
                {
                    Membership.DeleteUser(user.UserName, true);
                }
                else
                {
                    if (user.UserName.StartsWith("Temp_"))
                    {
                        Logging.Logger.Log("User", "ClearAllUsers",
                            String.Format("Removing temporary user {0}.", user.UserName), "Info");

                        Membership.DeleteUser(user.UserName, true);

                    }
                }
            }

            if (clearAll)
            {
                string[] rolenames = Roles.GetAllRoles();
                foreach (string rolename in rolenames)
                {
                    string[] usernames = Roles.GetUsersInRole(rolename);
                    foreach (string username in usernames)
                    {
                        Roles.RemoveUserFromRole(username, rolename);
                    }
                    Logging.Logger.Log("User", "ClearAllUsers",
                        String.Format("Removing role {0}.", rolename), "Info");
                    Roles.DeleteRole(rolename);
                }
            }
        }

        /// <summary>
        /// Gets all the role names avaliable.
        /// </summary>
        public string[] RoleNames
        {
            get
            {
                string[] roleNames = Roles.GetAllRoles();
                if (roleNames.Length == 0)
                {
                    roleNames = new string[4] { "Administrator", "Project Manager", "Team Lead", "Developer" };
                    foreach (string role in roleNames)
                    {
                        if (!Roles.RoleExists(role))
                        {
                            Roles.CreateRole(role);
                        }
                    }
                }
                return roleNames;
            }
        }

        public bool ChangePassword(string userName, string oldPassword, string newPassword)
        {
            MembershipUserCollection users = Membership.FindUsersByName(userName);
            foreach (MembershipUser user in users)
            {
                if (user.UserName == userName)
                {
                    return user.ChangePassword(oldPassword, newPassword);
                }
            }
            return false;
        }
    }
}
